#ifndef OCTREE_H
#define OCTREE_H

#include <list>
#include "Triangle.h"
#include <windows.h>  // Header File For Windows
#include <gl\gl.h>	  // Header File For The OpenGL32 Library
#include <gl\glu.h>	  // Header File For The GLu32 Library

using namespace std;

class OctreeNode
{
private:
    static GLuint nextCallList;
    GLuint callList;
	OctreeNode* Children[8];
	bool leaf;
	float minX;
	float minY;
	float minZ;
	float maxX;
	float maxY;
	float maxZ;
	float fovy;
	float aspect;
	int numShapesCarried;
	int Threshold;
	int Depth;
	int MaxDepth;
	list<Triangle*> shapes;
    static GLuint GetNextCallList()
    {
        return nextCallList++;
    }
public:
	OctreeNode(float Xmin, float Ymin, float Zmin, float Xmax, float Ymax, float Zmax, int MyDepth, int MyMaxDepth, int MyThreshold, float fovy, float aspect, list<Triangle*>* l);
	~OctreeNode();
	void SetMinX(float Xmin);
	void SetMinY(float Ymin);
	void SetMinZ(float Zmin);
	void SetMaxX(float Xmax);
	void SetMaxY(float Ymax);
	void SetMaxZ(float Zmax);
	float GetMinX();
	float GetMinY();
	float GetMinZ();
	float GetMaxX();
	float GetMaxY();
	float GetMaxZ();
	list<Triangle*> GetShapes();
	bool IsInside(float x, float y, float z);
	void ReturnVisibleShapesSphere  (list<Triangle*>* l, float camx, float camy, float camz, float radius);
	void ReturnVisibleShapesFrustrum(list<Triangle*>* l, float camx, float camy, float camz, vec<float, 3> topnorm, vec<float, 3> bottomnorm, vec<float, 3> rightnorm, vec<float, 3> leftnorm);
    void ReturnVisibleShapesCallList(list<GLuint>*    l, float camx, float camy, float camz, vec<float, 3> topnorm, vec<float,3> bottomnorm, vec<float, 3> rightnorm, vec<float, 3> leftnorm);
};

class Octree
{
private:
	list<Triangle*> shapes;
	OctreeNode* Head;
	float fovy;
	float aspect;

	void FindMinAndMax(float& minx, float& miny, float& minz, float& maxx, float& maxy, float& maxz, list<Triangle*>* l);
public:
	Octree(list<Triangle*> l, float fovy, float aspect, int MaxThreshold, int MaxDepth = -1);
	~Octree();
	void ReturnVisibleShapesFrustrum(list<Triangle*>* l, float camx, float camy, float camz, float frontx, float fronty, float frontz, float upx, float upy, float upz, float rightx, float righty, float rightz);
    void ReturnVisibleShapesCallList(list<GLuint>*    l, float camx, float camy, float camz, float frontx, float fronty, float frontz, float upx, float upy, float upz, float rightx, float righty, float rightz);
	void ReturnVisibleShapesSphere  (list<Triangle*>* l, float camx, float camy, float camz, float radius);
};

#endif